//----------------------------------------------------------------------------
//
// (C) Copyrights MARIN/MSCN  2002 
//
//----------------------------------------------------------------------------
//
// $Source: /cvsdb/include/CC/radar/nodes/radNotifier.hxx,v $
//
// $State: Exp $
//
// $Locker:  $
//
// $Revision: 1.1 $
//
// $Date: 2002/06/11 13:59:46 $
//
// $Author: mscn $
//
// $Contractor: $
//
// $Project: $
//
// $Log: $
//
// $Description: $
//
// $End: $
//
//----------------------------------------------------------------------------

#ifndef __mst_Notifier_h__
#define __mst_Notifier_h__

#include "api.h"

/*
 * Avoid name clashes
 */
#ifdef None
#undef None
#endif
#ifdef Always
#undef Always
#endif

#ifdef __cplusplus

namespace mst {

/*!
  \class Notifier mst/Notifier.h
  \ingroup notifier
  \brief Control thread safe error handling, signal errors or log messages

  These functions provide a general purpose error message and notification
  handling facility for applications using the MST toolkit. This facility
  is used internally by the MST for error, warning, and status
  notifications and can be used by user developed programs as well.

  The following conveniance macros are defined:
  - mstNotify for notify
  - mstNotice for notice
  - mstInfo for info
  - mstDebug for debug
  - mstResource for resource
  - mstFatal for fatal
  - mstWarn for warn
  - mstMore for more
  - mstInternal for internal

  The Notifier can be controlled by three environment variables: the <b>prefix</b>NFYLEVEL, <b>prefix</b>NFYFORMAT and the
  <b>prefix</b>NFYURI environment variables which will override the programmatic settings. The <b>prefix</b>
  is replaced by the specified prefix string in the mst::init function or in the Notifier
  constructor or reinit function. The prefix defaults to the string MST.
  The <b>prefix</b>NFYLEVEL environment variable can be used to filter the messages. Once the threshold
  is set, only messages with a priority greater than or equal to the current level are outputted.
  Fatal errors cause the program to exit.
  The <b>prefix</b>NFYLEVEL can be set to the string values: None, Always, Fatal, Warn, Notice,
  Info, Debug, FpDebug and InternalDebug or to its corresponding integer value as specified in the
  Severity enumeration below.

  The <b>prefix</b>NFYURI environment variable controls the output device or file of the notifier. The
  following URI's are supported:
  - <b>"device:stdout"</b>
  Send the messages to the stdout which is the default.
  - <b>"device:stderr"</b>
  Send the messages to the stderr
  - <b>"device:null"</b>
  Send the messages to the null device which is /dev/null on an Unix/Linux system and nul
  on a MS Windows system.
  - <b>"device:console"</b>
  Send the messages to the console device which is /dev/console on an Unix/Linux system and
  stdout on a MS Windows system.
  - <b>"file:filename"</b>
  Send the messages to the specified file. For example: "file:/usr/tmp/notifier.log".
  - <b>"mcast://ip:port"</b>
  Send the messages to an multicast address and port. For example: mcast://224.10.10.10:100100
  Valid multicast addresses are in the range of 224.x.x.x - 239.x.x.x.

  The <b>prefix</b>NFYFORMAT environment variable controls the format of the
  output message. The default format prints out a message of the form:

  time;prefix;hostname;process_name;pid;serial;level;type;errno;message
  Or,

  time;prefix;hostname;process_name;pid;serial;level;type;message

  where pid is the process id of the process that encountered the error
  level is a string indicating the severity of the
  error, type is the type of error detected, errno is the value of the
  system global errno (see perror(3C)), and message is the formatted error
  message given notify.  

  The <b>prefix</b>NFYFORMAT can have the followinf formats:
  - long (this is the default)
  print a message in the format described above.
  - short
  print the message as: 'prefix;message'
  - asis
  print the message as: 'message'
  - time
  print the message as: 'time;message'

*/

  class NotifierImpl;

  class MSTAPI Notifier {
    public:
      /** \fn Notifier(const char *uri = "device:stdout",const char *prefix = "MST")
       * \brief Construct a Notifier object
       */
      Notifier(const char *uri = "device:stdout",
               const char *prefix = "MST");
      /** \fn virtual ~Notifier()
       * \brief Destruct a Notifier object
       */
      virtual ~Notifier();
	
      /** \fn virtual void reinit(const char *uri = "device:stdout",const char *prefix = "MST")
       * \brief Reinitialise a notifier
       */
      virtual void reinit(const char *uri = "device:stdout", const char *prefix = "MST");

      //! Severity threshold enumeration
      typedef enum { 
        None=0,		/*!< 0 Internal use only */
        Always=1, 	/*!< 1 Always print regardless of notify level */
        Fatal=2, 	/*!< 2 Fatal error, the dying gasp of a doomed process */
        Warn=3, 	/*!< 3 Serious warning, rarely used for frame-time errors */
        Notice=4, 	/*!< 4 Warning, may be used for frame time errors */
        Info=5, 	/*!< 5 Information on progress as well as errors */
        Debug=6,	/*!< 6 Debug information of significant verbosity */
        FpDebug=7, 	/*!< 7 Debug information and floating point exceptions */
        InternalDebug=8	/*!< 8 Internal debugging only */
      } Severity;

      //! Error types
      typedef enum {
        More=0,	/*!< Continuation of the previous message */
        Usage=1,	/*!< Usage error */
        Resource=2,	/*!< Resource error */
        SysErr=3,	/*!< System error */
        Assert=4,	/*!< Assertion not fulfilled */
        Print=5,	/*!< Print */
        Internal=6,	/*!< Internal error */
        FpOverflow=7,	/*!< Floating point overflow exception */
        FpDivZero=8,	/*!< Floating point divide by zero exception */
        FpInvalid=9,	/*!< Floating point invalid value exception */
        FpUnderflow=10/*!< Floating point underflow exception */
      } ErrorType;
    public:
      /*!	\fn void notify(Severity s, ErrorType t, const char *format, ...)
        \brief Generic notify function
      */
      void notify(Severity s, ErrorType t, const char *format, ...);

      /*!	\fn void notice(ErrorType t, const char *format, ...)
        \brief Notice severity level notify function
      */
      void notice(ErrorType t, const char *format, ...);

      /*!	\fn void notice(const char *format, ...)
        \brief Notice severity level notify function with Print error type
      */
      void notice(const char *format, ...);

      /*!	\fn void info(ErrorType t, const char *format, ...)
        \brief Info severity level notify function
      */
      void info(ErrorType t, const char *format, ...);

      /*!	\fn void info(const char *format, ...)
        \brief Info severity level notify function with Print error type
      */
      void info(const char *format, ...);

      /*!	\fn void resource(const char *format, ...)
        \brief Resource severity level notify function with Resource error type
      */
      void resource(const char *format, ...);

      /*!	\fn void debug(ErrorType t, const char *format, ...)
        \brief Debug severity level notify function
      */
      void debug(ErrorType t, const char *format, ...);

      /*!	\fn void debug(const char *format, ...)
        \brief Debug severity level notify function with Print error type
      */
      void debug(const char *format, ...);

      /*!	\fn void fatal(ErrorType t, const char *format, ...)
        \brief Fatal severity level notify function
      */
      void fatal(ErrorType t, const char *format, ...);

      /*!	\fn void fatal(const char *format, ...)
        \brief Fatal severity level notify function with Print error type
      */
      void fatal(const char *format, ...);

      /*!	\fn void warn(ErrorType t, const char *format, ...)
        \brief Warn severity level notify function
      */
      void warn(ErrorType t, const char *format, ...);

      /*!	\fn void warn(const char *format, ...)
        \brief Warn severity level notify function with Print error type
      */
      void warn(const char *format, ...);

      /*!	\fn void internal(ErrorType t, const char *format, ...)
        \brief Internal severity level notify function
      */
      void internal(ErrorType t, const char *format, ...);

      /*!	\fn void internal(const char *format, ...)
        \brief Internal severity level notify function with Print error type
      */
      void internal(const char *format, ...);

      /*!	\fn void more(Severity level, const char *format, ...)
        \brief Continuation function
      */
      void more(Severity level, const char *format, ...);

      /*!	\fn void assertion(bool exp, const char *format, ...)
        \brief Assertion function
      */
      void assertion(bool exp, const char *format, ...);

      /*!	\fn void notifyLevel(Severity level)
        \brief Sets the threshold for notification
        \param level The notification level

        A notification must have a level less than or equal to the
        threshold for the default handler to print a message. The notification
        handler itself is invoked regardless of the notification level.  The
        levels are in decreasing severity:
        - None
        - Always
        - Fatal
        - Warn
        - Notice
        - Info
        - Debug
        - FpDebug
        - InternalDebug

        The default notification threshold is Notice.
        Setting the notification level to FpDebug also enables
        floating point exceptions for overflow, underflow and invalid operations.
        Normally, these floating point errors are handled through kernel
        exceptions or by the floating point hardware, and may be nearly
        invisible to an application except from the performance degradation,
        sometimes very significant, which they can cause. When enabled, 
        Notifier events are generated for the floating point exceptions
        mentioned above and messages displayed or passed to the user supplied
        notify handler.

        The environment variable <b>prefix</b>NFYLEVEL can be set to override the value
        specified in notifyLevel. If the notification level is
        set via <b>prefix</b>NFYLEVEL it can not be changed by an application.
        A notification level of Fatal causes the program to exit
        after notification; less severe levels do not.

      */
      void notifyLevel(Severity level);

      /*!	\fn Severity getNotifyLevel() const
        \brief Query the current notification level
      */
      Severity getNotifyLevel() const;
	
      /*! 	\fn Notifier& operator=(const Notifier *v)
        \brief Notifier pointer assignment operator.
      */
      Notifier& operator=(const Notifier *v);

    private:
      Notifier(const Notifier &) : m_impl(0L) {}
      Notifier& operator=(const mst::Notifier&) { return *this; }

    private:
      NotifierImpl *m_impl;
  };

/*! \var notifier
  \brief The global notifier object
*/
  extern mst::Notifier MSTAPI &notifier;

}

/*
 * Conveniance macros
 */

/*!
  \def mstNotify(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstNotify mst::notifier.notify

/*!
  \def mstNotice(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstNotice mst::notifier.notice

/*!
  \def mstInfo(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstInfo mst::notifier.info

/*!
  \def mstDebug(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstDebug mst::notifier.debug

/*!
  \def mstFatal(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstFatal mst::notifier.fatal

/*!
  \def mstResource(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstResource mst::notifier.resource

/*!
  \def mstWarn(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstWarn mst::notifier.warn

/*!
  \def mstMore(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstMore mst::notifier.more

/*!
  \def mstInternal(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstInternal mst::notifier.internal

/*!
  \def mstAssert(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(Severity s, ErrorType t, const char *format, ...)
*/
#define mstAssert mst::notifier.assertion

/*!
  \def mstTrace(const char *fmt, ...)
  \ingroup notifier
  \brief Conveniant macro for mst::notifier.notify(mst::Notifier::Debug, mst::Notifier::Print, const char *format, ...)
*/
#define mstTrace() \
mst::notifier.notify(mst::Notifier::Debug,mst::Notifier::Print,"%d: %s",__LINE__,__FILE__)

#else

/*
 * C API
 */
/*! Severity threshold enumeration */
typedef enum { 
  Mst_None=0,	/*!< 0 Internal use only */
  Mst_Always=1, 	/*!< 1 Always print regardless of notify level */
  Mst_Fatal=2, 	/*!< 2 Fatal error, the dying gasp of a doomed process */
  Mst_Warn=3, 	/*!< 3 Serious warning, rarely used for frame-time errors */
  Mst_Notice=4, 	/*!< 4 Warning, may be used for frame time errors */
  Mst_Info=5, 	/*!< 5 Information on progress as well as errors */
  Mst_Debug=6,	/*!< 6 Debug information of significant verbosity */
  Mst_FpDebug=7, 	/*!< 7 Debug information and floating point exceptions */
  Mst_InternalDebug=8	/*!< 8 Internal debugging only */
} MstSeverity;

/*! Error types */
typedef enum {
  Mst_More=0,	/*!< Continuation of the previous message */
  Mst_Usage=1,	/*!< Usage error */
  Mst_Resource=2,	/*!< Resource error */
  Mst_SysErr=3,	/*!< System error */
  Mst_Assert=4,	/*!< Assertion not fulfilled */
  Mst_Print=5,	/*!< Print */
  Mst_Internal=6,	/*!< Internal error */
  Mst_FpOverflow=7,	/*!< Floating point overflow exception */
  Mst_FpDivZero=8,	/*!< Floating point divide by zero exception */
  Mst_FpInvalid=9,	/*!< Floating point invalid value exception */
  Mst_FpUnderflow=10/*!< Floating point underflow exception */
} MstErrorType;

extern void cmstNotify(MstSeverity s, MstErrorType t, const char *format, ...);
extern void cmstNotice(MstErrorType t, const char *format, ...);
extern void cmstInfo(MstErrorType t, const char *format, ...);
extern void cmstDebug(MstErrorType t, const char *format, ...);
extern void cmstFatal(MstErrorType t, const char *format, ...);
extern void cmstResource(const char *format, ...);
extern void cmstWarn(MstErrorType t, const char *format, ...);
extern void cmstInternal(MstErrorType t, const char *format, ...);
extern void cmstAssert(bool exp, const char *format, ...);

#endif

#endif

